/*
 * This File is a simple sniffer in C
 *
 * Author : Tuhin Shanakar Dey
 * 			tuhin.shankar.dey@gmail.com
 *
 * This simple sniffer is a free software;
 * the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * The orca sniffer implementation is distributed in the hope that it 
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *                 ************************
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU CC; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Please report any bugs/suggestions to the email provided above.
 */

#include "orca_sniff.h" 

struct	ethhdr	*orca_eth = (struct ethhdr *)msg;
//struct	ethhdr *orca_eth = (struct ethhdr *)(&recvBuf.recv_buffer);
struct 	ip		*orca_iphdr;
struct 	tcphdr	*orca_tcphdr;
struct 	udphdr	*orca_udphdr;
struct 	icmphdr	*orca_icmphdr;
struct 	arphdr	*orca_arphdr;

/*
 * Routine to classify 
 * protocols and
 * display them
 */
void show_proto (int i)
{
    int proto;	

 	/* This will change the endianness */
	proto = ((i>>8) & 0xff) + ((i << 8) & 0xff00);
	printf ("\nProtocol: 0x0%2.2X %d \n", proto, ntohl(i));
	//printf ("\n\n\n%d\n\n\n", i);	
	if (i == 1544)
	{
		printf ("Layer 2 protocol: ARP (0x0%2.2X)\n", proto);
		orca_arphdr = (struct arphdr *) (msg + sizeof (struct ethhdr));
		printf ("Hardware type: %d", (((orca_arphdr->ar_hrd)>>8)&0xff) + 
            (((orca_arphdr->ar_hrd) << 8)&0xff00));
		if (1 == (((orca_arphdr->ar_hrd)>>8)&0xff) + 
	    	(((orca_arphdr->ar_hrd) << 8)&0xff00))
			printf (" (Ethernet)\n");
		else 
			printf ("\n");

		printf ("Protocol Type: %d", orca_arphdr->ar_pro);
		if (8 == orca_arphdr->ar_pro)
			printf (" (IP)\n");
		else
			printf ("\n");

		/*display the data inside header*/
		printf ("Hardware Length: %d\n", orca_arphdr->ar_hln); 
		printf ("Protocol Length: %d\n", orca_arphdr->ar_pln);

	/*Correct the endian-ness and print */
	int opcode = (((orca_arphdr->ar_op)>>8)&0xff) +
                (((orca_arphdr->ar_op) << 8)&0xff00);

	printf ("%d----- \n", opcode);	
	printf ("opcode: 0x0%2.2X", (((orca_arphdr->ar_op)>>8)&0xff) + 
		(((orca_arphdr->ar_op) << 8)&0xff00));

	if (256 == orca_arphdr->ar_op)
	{
	    printf (" (request)\n");
	    printf ("%d \n", opcode);	
	}
	
	else if (512 == orca_arphdr->ar_op)
	{
	    printf (" (reply)\n");
	    printf ("%d \n", opcode);	
	}
    }

    else if (i == 36864)
	printf ("Layer 2 protocol: Loopback (0x0%2.2X)\n", proto);

    else if (i == 32923)
	printf ("Layer 2 protocol: AppleTalk (0x0%2.2X)\n", proto);	

    else if (i == 8)
    {	
	printf ("Layer 3 protocol: IPv4 (0x0%2.2X)\n", proto);
	orca_iphdr = (struct ip *)(msg + sizeof (struct ethhdr));

	printf ("Source          %d\n", inet_ntoa (orca_iphdr->ip_src));
	printf ("Destination     %d\n", inet_ntoa (orca_iphdr->ip_dst));

	if (orca_iphdr->ip_p == 1)
	{
		printf ("Layer 3 protocol: ICMP ");
		orca_icmphdr = (struct icmphdr *) (msg + sizeof (struct ethhdr) + 
			sizeof (struct ip));
		
		if (orca_icmphdr->type == ICMP_ECHO)
		    printf ("type: ICMP_ECHO\n");

		else if (orca_icmphdr->type == ICMP_ECHOREPLY)
		    printf ("type: ICMP_REPLY\n");
	}

	else if (orca_iphdr->ip_p == 6)
	{
	    printf ("Layer 4 protocol: TCP\n");
	    orca_tcphdr = (struct tcphdr *) (msg + sizeof (struct ethhdr) + 
		sizeof (struct ip));	
	}

	else if (orca_iphdr->ip_p == 17)
	{
	    printf ("Layer 4 protocol: UDP\n");		
	    orca_udphdr = (struct udphdr *) (msg + sizeof (struct ethhdr) + 
		sizeof (struct ip));
	}
	else if (orca_iphdr->ip_p == 112)
        {
            printf ("Layer 3 protocol: VRRP\n");
        }
		printf ("\n\n\n %d \n\n\n", orca_iphdr->ip_p);	
    }

    else if (i == 56710)
	printf ("Layer 3 protocol: IPv6 (0x0%2.2X)\n", proto);	
	
    else 
	printf ("(0x0%2.2X) , %d\n", proto, proto);	
}

/*
 *This will listen to all packets
 *at the link layer
 */	

int main(void) 
{
    int					socketfd,j;
    struct	sockaddr_ll	skaddr;
    socklen_t			len;

    skaddr.sll_protocol = htons(ETH_P_ALL);
    socketfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 
    len = sizeof(struct sockaddr);
    bind (socketfd, (struct sockaddr*) &skaddr, len);
 
    while (1) 
    {
		recvfrom(socketfd, msg, sizeof (msg), 0, 
			(struct sockaddr*) &skaddr, &len);
		printf ("===================================================\n");
		printf ("Ethernet\n");
		int protocol_num = orca_eth->h_proto;
		show_proto (protocol_num);	
		show_eth_frame (orca_eth);	  
		for(j=0; j<20; j++)
			printf("0x%2.2X", msg[j] & 0x000000FF);
		printf("\n");
    }

    close(socketfd);
    return;
}

